Skip to content

fix(engine,web): emit iteration_limit_reached/resolved events for dashboard#162

Merged
jrob5756 merged 2 commits intomainfrom
fix/134-iteration-limit-dashboard-event
May 6, 2026
Merged

fix(engine,web): emit iteration_limit_reached/resolved events for dashboard#162
jrob5756 merged 2 commits intomainfrom
fix/134-iteration-limit-dashboard-event

Conversation

@jrob5756
Copy link
Copy Markdown
Collaborator

@jrob5756 jrob5756 commented May 6, 2026

Closes #134

Problem

When a workflow hit its max_iterations limit, the engine prompted the user via a console-only Rich IntPrompt while the web dashboard went silently dark — the last visible event was an agent_completed, then nothing. Users monitoring via --web had no indication that the workflow was paused or what action was needed; they had to switch to the console terminal to discover the prompt.

Backend

Two new event types emitted from _check_iteration_with_prompt and _check_parallel_group_iteration_with_prompt in engine/workflow.py:

  • iteration_limit_reached — emitted before the console prompt:

    {
      "agent_name": "reviewer",        // or "group_name" for parallel
      "current_iteration": 20,
      "max_iterations": 20,
      "agent_history": ["architect", "reviewer", "architect", "reviewer", "architect"],
      "possible_loop": true,
      "skip_gates": false
    }
  • iteration_limit_resolved — emitted after the prompt:

    {
      "agent_name": "reviewer",
      "continue_execution": true,
      "additional_iterations": 10
    }

The possible_loop heuristic flags when the last 3 history entries are the same agent — a strong signal for a stuck review loop. The skip_gates flag lets subscribers distinguish interactive gates from auto-stop scenarios.

The console subscriber and JSONL log subscriber needed no changes — the existing console prompt continues to drive interactive resolution; the new events are purely additive for downstream consumers.

Frontend

  • types/events.ts — added the two event types and matching IterationLimitReachedData / IterationLimitResolvedData interfaces.
  • workflow-store.ts — added an iterationLimitGate slice (set on reached, cleared on resolved). Both events produce activity-log and event-log entries on the relevant agent/group node.
  • StatusBar.tsx — shows an amber-tinted banner "Iteration limit reached: N/N — awaiting console input" when the gate is open, falling back to normal status text when resolved.

Bundled web/static/ assets rebuilt via npm run build (the standard build pipeline).

Tier-1 fix only

This PR delivers the dashboard-visibility half of the issue (emit events, render the gate). It does not make the gate web-resolvable from the dashboard — the user still answers via the console prompt. Web-resolvable iteration gates would require bidirectional WebSocket coordination similar to human gates and is out of scope for this fix.

Tests

Verification

In a workflow with a tight max_iterations limit and --web, the dashboard now:

  1. Emits iteration_limit_reached → StatusBar turns amber: "Iteration limit reached: reviewer 20/20 — awaiting console input"
  2. User responds in console → iteration_limit_resolved clears the gate and StatusBar returns to normal.

jrob5756 and others added 2 commits May 6, 2026 09:49
…hboard

Closes #134

When a workflow hit its `max_iterations` limit, the engine's interactive
prompt was console-only — no event was emitted, so the web dashboard
went dark with the last visible event being an `agent_completed`. Users
monitoring via `--web` had no indication that the workflow was paused
or what action was needed.

## Backend

Two new event types emitted from `_check_iteration_with_prompt` and
`_check_parallel_group_iteration_with_prompt` in `engine/workflow.py`:

- `iteration_limit_reached` — emitted **before** the console prompt with
  `{agent_name|group_name, current_iteration, max_iterations,
    agent_history (last 5), possible_loop, skip_gates}`.
- `iteration_limit_resolved` — emitted **after** the prompt with
  `{agent_name|group_name, continue_execution, additional_iterations}`.

The `possible_loop` heuristic flags when the last 3 history entries are
the same agent (signal for a stuck review loop). The `skip_gates` flag
tells subscribers whether the gate is interactive or about to auto-stop.

The console subscriber and JSONL log subscriber require no changes —
the existing console prompt UI still drives interactive resolution; the
new events are additive for downstream consumers.

## Frontend

- New `EventType` entries in `types/events.ts` plus
  `IterationLimitReachedData` / `IterationLimitResolvedData`
  interfaces.
- New `iterationLimitGate` slice in `workflow-store.ts` (set on
  reached, cleared on resolved); both events also produce activity-log
  and event-log entries.
- `StatusBar.tsx` shows an amber-tinted banner
  "Iteration limit reached: <agent> N/N — awaiting console input"
  when the gate is open, falling back to the normal status when
  resolved.

Bundled `web/static/` assets rebuilt via `npm run build`.

## Tests

- New `tests/test_engine/test_iteration_limit_events.py` with 3 cases:
  reached event payload + skip_gates flag + possible_loop heuristic;
  resolved event in skip_gates mode; reached emitted before resolved.
- `make lint` clean.
- Full suite: 2374 passed (1 unrelated live Copilot integration test
  excluded).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address PR #162 review findings.

Critical: iteration_limit_resolved is now wrapped in an outer finally so
the dashboard gate always closes — even when the prompt itself raises
(EOFError on non-TTY, KeyboardInterrupt race, asyncio.CancelledError,
unexpected console errors). Without this guarantee, the original #134
symptom (silently dark dashboard) recurs on the error path. The resolved
event now carries an `aborted: bool` flag so subscribers can distinguish
exception-driven stops from deliberate ones. Applied to both the
single-agent and parallel-group helpers.

human.py: _prompt_for_additional_iterations now also catches EOFError
(non-TTY environments like CI, '< /dev/null', containers without a
terminal). Treated as "stop", same as the user typing 0.

Frontend hardening:
- workflow-store.ts: null iterationLimitGate in workflow_completed and
  workflow_failed (defense-in-depth — orphan gate banner cannot persist
  past terminal workflow states). Inline gate type replaced with
  IterationLimitReachedData | null so future fields propagate (already
  fixed an agent_count drift). Both event handlers warn when target
  name is missing.
- events.ts: IterationLimitReachedData and IterationLimitResolvedData
  are now discriminated unions on agent_name XOR group_name+agent_count
  (eliminates 4 illegal states + the `?? ?? 'workflow'` fallback chain
  consumers had to write). Always-emitted fields (possible_loop,
  skip_gates, agent_history, additional_iterations) marked required.
  Added optional aborted field. JSDoc tightened to describe the
  last-3-same-agent heuristic and the skip_gates auto-decision.

Tests grew 3 -> 10 cases covering: interactive continue path, interactive
decline path, prompt-raises-aborted path, EOFError-clean-stop path,
parallel-group emission site, possible_loop=False for mixed history,
possible_loop=False for short history, and a strengthened ordering test
that asserts no agent events fall between reached/resolved.

make lint, make typecheck, tsc -b && vite build all clean.
Full suite: 2382 passed, 9 skipped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756 jrob5756 merged commit aa2fb17 into main May 6, 2026
7 checks passed
@jrob5756 jrob5756 deleted the fix/134-iteration-limit-dashboard-event branch May 6, 2026 16:24
@jrob5756 jrob5756 mentioned this pull request May 6, 2026
jrob5756 added a commit that referenced this pull request May 6, 2026
- conductor resume flag parity with run (#158)
- reasoning effort displayed in dashboard (#160)
- iteration_limit_reached/resolved events for dashboard (#162)
- registry latest now means default branch HEAD, not newest tag (#157)
- forbid extra fields on Agent/Parallel/ForEach/Workflow schemas (#159)
- pretty-print tool args/results in dashboard events (#161)
- capture uv stdout+stderr on Windows install failure (#156)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Max iterations limit gate not visible in web dashboard — no event emitted

1 participant